<template>
  <!-- 自定义无缝滚动容器 -->
  <div class="custom-scroll-container" :style="containerStyle" ref="scrollContainer" @mouseenter="stopScroll"
    @mouseleave="startScroll" @wheel="handleWheel" @touchstart="handleTouchStart" @touchmove="handleTouchMove"
    @touchend="handleTouchEnd">
    <div class="scroll-content" ref="scrollContent">
      <!-- 原始内容 -->
      <div class="scroll-item" v-for="(item, index) in items" :key="`original_${getItemKey(item, index)}`">
        <slot name="item" :item="item" :index="index">{{ defaultItemRender(item, index) }}</slot>
      </div>
      <!-- 克隆内容用于无缝循环 -->
      <div class="scroll-item" v-for="(item, index) in items" :key="`clone_${getItemKey(item, index)}`">
        <slot name="item" :item="item" :index="index">{{ defaultItemRender(item, index) }}</slot>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts" name="Vue3AutoScroll">
import { ref, onMounted, onUnmounted, nextTick, computed } from 'vue'

// 定义组件属性
const props = defineProps({
  // 滚动数据列表
  items: {
    type: Array as () => Array<any>,
    required: true
  },
  // 滚动速度
  speed: {
    type: Number,
    default: 1
  },
  // 滚动方向 ('up' 或 'down')
  direction: {
    type: String,
    default: 'up',
    validator: (val: string) => ['up', 'down'].includes(val)
  },
  // 容器高度
  height: {
    type: String,
    default: '300px'
  },
  // 容器宽度
  width: {
    type: String,
    default: '100%'
  },
  // 自定义项的key获取函数
  getItemKey: {
    type: Function,
    default: (item: any, index: number) => item.id || `item_${index}`
  }
})

// 计算容器样式
const containerStyle = computed(() => ({
  height: props.height,
  width: props.width
}))

// 滚动容器和内容的引用
const scrollContainer = ref<HTMLElement | null>(null);
const scrollContent = ref<HTMLElement | null>(null);

// 滚动控制变量
let scrollAnimation: number | null = null;
let isAutoScrolling = false;
let scrollPosition = 0; // 当前滚动位置

// 触摸相关变量
let startY = 0; // 触摸开始的Y坐标
let startTime = 0; // 触摸开始的时间戳
let isDragging = false; // 是否正在拖动
let touchScrollPosition = 0; // 触摸开始时的滚动位置
let lastTouchY = 0; // 上一次触摸的Y坐标
let velocity = 0; // 滑动速度
let momentumTimer: number | null = null; // 动量滚动计时器

// 默认的项渲染函数
const defaultItemRender = (item: any, index: number) => {
  if (typeof item === 'string' || typeof item === 'number') {
    return item
  }
  return item.name || JSON.stringify(item)
}

// 启动自动滚动
function startScroll() {
  if (!scrollContent.value || !scrollContainer.value || isAutoScrolling) return;

  isAutoScrolling = true;
  const animateScroll = () => {
    if (!scrollContent.value || !scrollContainer.value || !isAutoScrolling) return;

    // 根据方向计算滚动位置增量
    const directionFactor = props.direction === 'up' ? 1 : -1;
    scrollPosition += props.speed * directionFactor;

    // 获取单个内容高度（假设所有内容项高度相同）
    const scrollItems = scrollContent.value.querySelectorAll('.scroll-item');
    if (scrollItems.length === 0) return;

    const singleHeight = (scrollItems[0] as HTMLElement).offsetHeight;
    const originalListHeight = singleHeight * props.items.length;

    // 实现无缝循环：当滚动超过原始内容长度时，重置位置
    if (props.direction === 'up') {
      if (scrollPosition >= originalListHeight) {
        scrollPosition = scrollPosition % originalListHeight;
      }
    } else {
      if (scrollPosition <= -originalListHeight) {
        scrollPosition = scrollPosition % (-originalListHeight);
      }
    }

    // 应用滚动位置
    scrollContent.value.style.transform = `translateY(-${scrollPosition}px)`;

    // 继续动画循环
    scrollAnimation = requestAnimationFrame(animateScroll);
  };

  // 开始动画循环
  animateScroll();
}

// 停止自动滚动
function stopScroll() {
  if (scrollAnimation) {
    cancelAnimationFrame(scrollAnimation);
    scrollAnimation = null;
  }
  isAutoScrolling = false;
}

// 处理鼠标滚轮事件
function handleWheel(event: WheelEvent) {
  if (!scrollContent.value || !scrollContainer.value) return;

  // 停止自动滚动
  stopScroll();

  // 根据滚轮方向调整滚动位置
  const delta = event.deltaY > 0 ? 10 : -10; // 每次滚轮滚动的距离
  scrollPosition = Math.max(0, scrollPosition + delta);

  // 获取内容总高度
  const scrollItems = scrollContent.value.querySelectorAll('.scroll-item');
  if (scrollItems.length === 0) return;

  const singleHeight = (scrollItems[0] as HTMLElement).offsetHeight;
  const maxScrollHeight = singleHeight * props.items.length; // 最大滚动高度为原始内容长度

  // 限制滚动范围
  scrollPosition = Math.min(scrollPosition, maxScrollHeight);

  // 应用滚动位置
  scrollContent.value.style.transform = `translateY(-${scrollPosition}px)`;

  // 阻止默认滚动行为
  event.preventDefault();
}

// 处理触摸开始事件
function handleTouchStart(event: TouchEvent) {
  if (!scrollContent.value || !scrollContainer.value) return;

  // 停止自动滚动和动量滚动
  stopScroll();
  if (momentumTimer) {
    clearTimeout(momentumTimer);
    momentumTimer = null;
  }

  // 记录触摸起始位置和时间
  startY = event.touches[0].clientY;
  startTime = Date.now();
  touchScrollPosition = scrollPosition;
  lastTouchY = startY;
  isDragging = true;
}

// 处理触摸移动事件
function handleTouchMove(event: TouchEvent) {
  if (!scrollContent.value || !scrollContainer.value || !isDragging) return;

  const currentY = event.touches[0].clientY;
  const diff = currentY - startY;

  // 计算速度
  const currentTime = Date.now();
  const timeDiff = currentTime - startTime;
  if (timeDiff > 50) {
    const yDiff = currentY - lastTouchY;
    velocity = yDiff / timeDiff; // 像素/毫秒
    lastTouchY = currentY;
    startTime = currentTime;
  }

  // 计算新的滚动位置
  let newPosition = touchScrollPosition - diff;

  // 获取内容高度信息
  const scrollItems = scrollContent.value.querySelectorAll('.scroll-item');
  if (scrollItems.length === 0) return;

  const singleHeight = (scrollItems[0] as HTMLElement).offsetHeight;
  const maxScrollHeight = singleHeight * props.items.length;

  // 应用一些弹性效果
  if (newPosition < 0) {
    // 顶部弹性效果
    const bounceFactor = 0.5;
    newPosition = newPosition * bounceFactor;
  } else if (newPosition > maxScrollHeight) {
    // 底部弹性效果
    const bounceFactor = 0.5;
    newPosition = maxScrollHeight + (newPosition - maxScrollHeight) * bounceFactor;
  }

  // 更新滚动位置
  scrollPosition = newPosition;

  // 应用滚动位置
  scrollContent.value.style.transform = `translateY(-${scrollPosition}px)`;

  // 阻止默认行为（如页面滚动）
  event.preventDefault();
}

// 处理触摸结束事件
function handleTouchEnd() {
  if (!scrollContent.value || !scrollContainer.value) return;

  isDragging = false;

  // 获取内容高度信息
  const scrollItems = scrollContent.value.querySelectorAll('.scroll-item');
  if (scrollItems.length === 0) return;

  const singleHeight = (scrollItems[0] as HTMLElement).offsetHeight;
  const maxScrollHeight = singleHeight * props.items.length;

  // 限制滚动位置在有效范围内
  if (scrollPosition < 0) {
    scrollPosition = 0;
  } else if (scrollPosition > maxScrollHeight) {
    scrollPosition = maxScrollHeight;
  }

  // 应用最终滚动位置
  scrollContent.value.style.transform = `translateY(-${scrollPosition}px)`;

  // 处理滑动动量效果
  const speedThreshold = 0.5; // 最小速度阈值
  const friction = 0.95; // 摩擦系数

  if (Math.abs(velocity) > speedThreshold) {
    let currentVelocity = velocity * 20; // 增强速度

    const applyMomentum = () => {
      if (!scrollContent.value || !scrollContainer.value) return;

      // 应用速度
      scrollPosition -= currentVelocity;

      // 检查边界
      let clamped = false;
      if (scrollPosition < 0) {
        scrollPosition = 0;
        clamped = true;
      } else if (scrollPosition > maxScrollHeight) {
        scrollPosition = maxScrollHeight;
        clamped = true;
      }

      // 应用滚动位置
      scrollContent.value.style.transform = `translateY(-${scrollPosition}px)`;

      // 减速
      currentVelocity *= friction;

      // 继续动量效果或停止
      if (!clamped && Math.abs(currentVelocity) > 0.5) {
        momentumTimer = requestAnimationFrame(applyMomentum);
      } else {
        // 动量效果结束，恢复自动滚动
        momentumTimer = setTimeout(() => {
          startScroll();
        }, 500); // 延迟500ms恢复自动滚动
      }
    };

    applyMomentum();
  } else {
    // 如果没有足够的动量，延迟恢复自动滚动
    momentumTimer = setTimeout(() => {
      startScroll();
    }, 500);
  }
}

// 组件挂载后初始化
onMounted(async () => {
  await nextTick();
  // 确保滚动容器和内容已经渲染
  if (scrollContent.value && scrollContainer.value) {
    // 为了确保无缝滚动效果，设置内容容器的过渡
    scrollContent.value.style.transition = 'transform 0s linear';
    // 启动自动滚动
    startScroll();
  }
});

// 组件卸载时清理
onUnmounted(() => {
  stopScroll();
  if (momentumTimer) {
    clearTimeout(momentumTimer);
  }
});
</script>

<style scoped lang="scss">
/* 自定义滚动容器样式 */
.custom-scroll-container {
  overflow: hidden;
  position: relative;
  cursor: pointer;
  -webkit-overflow-scrolling: touch;
  /* iOS滚动优化 */
  -ms-overflow-style: none;
  /* IE滚动条隐藏 */
  scrollbar-width: none;
  /* Firefox滚动条隐藏 */

  &::-webkit-scrollbar {
    display: none;
    /* Chrome, Safari滚动条隐藏 */
  }
}

.scroll-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

.scroll-item {
  background-color: #ffffff;
  transition: background-color 0.3s;

  &:hover {
    background-color: #fafafa;
  }
}

/* 暗黑模式适配 */
.dark .scroll-item {
  background-color: rgba(255, 255, 255, 0.05);

  &:hover {
    background-color: rgba(255, 255, 255, 0.1);
  }
}
</style>